;; supercollider/buffer.scm - (c) rohan drape, 2003-2005

;; A buffer is named using an <integer> index.  These procedures alias
;; the server buffer operation commands.  The only advantage in using
;; these interfaces is that asynchronous commands are made synchronous
;; by default (there is a `synchronous' flag that can be set to '#f').

(defineK (buffer-alloc (frames 64)
		       (channels 1)
		       (synchronous #t))
  (let ((b (bID)))
    (server-request*
     synchronous
     "/done"
     (list "/b_alloc" b frames channels))
    b))

(defineK (buffer-alloc-read (path "default") 
			    (file-start-frame 0) 
			    (frames -1) 
			    (synchronous #t))
  (let ((b (bID)))
    (server-request* 
     synchronous
     "/done"
     (list "/b_allocRead" b path file-start-frame frames))
    b))

(defineK (buffer-read (b #f)
		      (path "default") 
		      (file-start-frame 0) 
		      (frames -1) 
		      (buffer-start-frame 0)
		      (leave-file-open #f)
		      (synchronous #t))
  (server-request* 
   synchronous
   "/done"
   (list "/b_read" 
	 b path 
	 file-start-frame frames buffer-start-frame 
	 leave-file-open)))

(defineK (buffer-write (b #f)
		       (path "default") 
		       (header-format "aiff") 
		       (sample-format "float") 
		       (frames -1) 
		       (buffer-start-frame 0) 
		       (leave-file-open 0) 
		       (synchronous #t))
  (server-request* 
   synchronous
   "/done"
   (list "/b_write"
	 b 
	 path header-format sample-format 
	 frames buffer-start-frame leave-file-open)))

(defineK (buffer-free (b #f) (synchronous #t))
  (server-request* 
   synchronous 
   "/done" 
   (list "/b_free" b))
  (bID-release b))

(defineK (buffer-zero (b #f) (synchronous #t))
  (server-request* 
   synchronous 
   "/done" 
   (list "/b_zero" b)))

(define (buffer-set b . values)
  (server-send-message `("/b_set" ,b ,@values)))

(define (buffer-setn b . values)
  (server-send-message `("/b_setn" ,b ,@values)))

(define (buffer-setn* b . values)
  (apply buffer-setn b 
	 (append-map (lambda (e)
		       (cons (car e) (cons (length (cdr e)) (cdr e))))
		     values)))

(define (buffer-fill b . values)
  (-> "/b_fill" b values))

(define (buffer-gen b command . values)
  (-> "/b_gen" b command values))

(define (buffer-close b)
  (-> "/b_close" b))

(define (buffer-query b)
  (->< "/b_info" "/b_query" b))

(define (buffer-get b . i)
  (apply ->< "/b_set" "/b_get" b i))

(define (buffer-getn b i n)
  (->< "/b_setn" "/b_getn" b i n))

;; Run the 'sine1' gen function at the buffer `b'.  The `amplitudes'
;; list has an element for each partial.  The `normalize' and
;; `clearFirst' clear first flags are self explanatory, the
;; `asWavetable' flag should be set if the buffer is to be used by an
;; SC3 interpolating oscillator.

(defineK (buffer-sine1 (b #f)
		       (amplitudes '(1)) 
		       (normalize #f) 
		       (asWavetable #f) 
		       (clearFirst #f))
  (apply -> "/b_gen"
	 b
	 "sine1"
	 (+ (if normalize 1 0)
	    (if asWavetable 2 0)
	    (if clearFirst 4 0))
	 amplitudes))

;; Sequence of /b_alloc and /b_read.  Allocate a buffer at the server
;; `server' to be used with a DiskIn UGen.

(defineK (buffer-cue-sound-file (path "default")
				(file-start-frame 0) 
				(channels 2) 
				(buffer-size 32768) 
				(synchronous #t))
  (let ((b (buffer-alloc buffer-size channels synchronous)))
    (buffer-read b path file-start-frame -1 0 1 1)
    b))
